import { _decorator, Component, Node, Camera, MeshRenderer, RenderTexture, director, Vec3, v3, Quat, quat, Texture2D, color,screen, gfx, Layers } from 'cc';
import { BuildCtrl } from './deco/BuildCtrl';
const { ccclass, property } = _decorator;
const v0 = new Vec3();

@ccclass('ReflectMgr')
export class ReflectMgr extends Component {
    
    @property({ type: Camera })
    mainCamera: Camera = null;
    @property
    scale = 0.3;

    private _refelctionCamera: Camera = null;

    static ins:ReflectMgr
    private reflectionRT:RenderTexture;

    private _initted = false;

    private _selfDot: number = 0;
    private _selfPos: Vec3 = v3();

    private _tmpV3_0: Vec3 = v3();
    private _tmpV3_1: Vec3 = v3();
    private _tmpV3_N: Vec3 = v3();
    private _tmpQuat: Quat = quat();


    start(){
        ReflectMgr.ins = this;
        this.init();
    }
    
    init() {
        if (!this.mainCamera||this._initted) {
            return;
        }
        this.initReflection();
        BuildCtrl.ins.floorMaterial.setProperty('reflectionMap', this.reflectionRT);
        BuildCtrl.ins.toiletMat.setProperty('reflectionMap', this.reflectionRT);
        BuildCtrl.ins.roomMaterial.setProperty('reflectionMap', this.reflectionRT);

        v0.x = -1;

        Quat.fromEuler(this._tmpQuat,-90,0,0);

        Vec3.transformQuat(this._selfPos, Vec3.FORWARD, this._tmpQuat);

        let n = this._selfPos;

        n.negative();
        n.normalize();

        this._selfDot = Vec3.dot(v0, n);
        this._initted =true;

    }

    disable(){
        if (!this._initted) {
            return;
        }
        this._initted = false;

        this._refelctionCamera.visibility = null;
      

    }


    
    lateUpdate() {
     
        if (this._initted) {

            let target = this.mainCamera.node;
            let source = this._refelctionCamera.node;

            //position.
            this.getMirrorPoint(this._tmpV3_0, target.position, this._selfPos, this._selfDot);
            source.setPosition(this._tmpV3_0);
            //forward
            this._tmpV3_0.set(target.forward);
            this.getMirrorPoint(this._tmpV3_0, this._tmpV3_0, this._selfPos, 0);
            this._tmpV3_0.normalize();
            this._tmpV3_0.negative();
            //up
            Vec3.transformQuat(this._tmpV3_1, Vec3.UP, target.rotation);
            this.getMirrorPoint(this._tmpV3_1, this._tmpV3_1, this._selfPos, 0);
            this._tmpV3_1.normalize();
            //calculate rotation with view(forward) and up directions
            Quat.fromViewUp(this._tmpQuat, this._tmpV3_0, this._tmpV3_1);
            source.setRotation(this._tmpQuat);
            this._refelctionCamera.fov  = this.mainCamera.fov;

        }
    }

    initReflection() {
        if(!this.reflectionRT){
            this.reflectionRT= this.createRenderTexture('reflection_rt');
        }

        if(!this._refelctionCamera){
            let node = new Node();
            director.getScene().addChild(node);
            this._refelctionCamera = node.addComponent(Camera);
            this._refelctionCamera.clearFlags = 7;
            this._refelctionCamera.clearColor = color(0,0,0,0);
            this._refelctionCamera.priority = this.mainCamera.priority - 1;
            this._refelctionCamera.targetTexture = this.reflectionRT;
            this._refelctionCamera.name = 'Refelction Camera';
            this._refelctionCamera.fov  = this.mainCamera.fov;
            this._refelctionCamera.near = this.mainCamera.near;
            this._refelctionCamera.far = 60;
        }
        this._refelctionCamera.visibility = Layers.Enum.UI_3D ;

    
    }

    public getMirrorPoint(out: Vec3, p: Vec3, n: Vec3, d: number): Vec3 {
     
        let dist = Vec3.dot(p, n) - d;
        //tmp = N
        this._tmpV3_N.set(n).multiplyScalar(2.0 * dist);;
        //tmp = 2.0 * dist * N
        // out = p - 2.0 * dist * N
        Vec3.subtract(out, p, this._tmpV3_N);
        return out;
    }

    getSize(){
        let size = screen.windowSize;
        let dpr = Math.min(1, screen.devicePixelRatio);
        let width = size.width * dpr * 0.3;
        let height = size.height * dpr * 0.3;
        let ratio = width / height;
        const max = 1280 * this.scale;
        if (width > max) {
            width = max;
            height = ~~(width / ratio);
        }
        if (height > max) {
            height = max;
            width = ~~(height * ratio);
        }
        console.log("rect"+this.mainCamera.rect)
        width*=this.mainCamera.rect.z;
        height*=this.mainCamera.rect.w;

        return [width, height]

    }
    public createRenderTexture(usage:string, numOfColors: number = 1): RenderTexture {
        let texture = new RenderTexture();
   
        let colors = [];
        for (let i = 0; i < numOfColors; ++i) {
            colors.push(new gfx.ColorAttachment(gfx.Format.RGBA8));
        }

        const size = this.getSize();

        texture.reset({
            width: size[0], height: size[1],

        });

        texture.setFilters(Texture2D.Filter.LINEAR, Texture2D.Filter.LINEAR);
        texture.setWrapMode(Texture2D.WrapMode.CLAMP_TO_BORDER, Texture2D.WrapMode.CLAMP_TO_BORDER);

        return texture;
    }

}